home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procRemote.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  36KB  |  1,218 lines

  1. /* 
  2.  * procRemote.c --
  3.  *
  4.  *    Routines for a remote workstation to handle process migration.  This
  5.  *    involves the following:
  6.  *
  7.  *        - Grant permission to another workstation to migrate to this
  8.  *          one.
  9.  *        - Accept the process from the other workstation, creating a
  10.  *          local copy of it.
  11.  *        - Execute the process, sending system calls back to the home
  12.  *          node for processing.
  13.  *        - Transfer the process back to the home node upon termination.
  14.  *
  15.  * Copyright 1986, 1988 Regents of the University of California
  16.  * Permission to use, copy, modify, and distribute this
  17.  * software and its documentation for any purpose and without
  18.  * fee is hereby granted, provided that the above copyright
  19.  * notice appear in all copies.  The University of California
  20.  * makes no representations about the suitability of this
  21.  * software for any purpose.  It is provided "as is" without
  22.  * express or implied warranty.
  23.  */
  24.  
  25. #ifndef lint
  26. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procRemote.c,v 9.17 92/06/15 22:29:36 jhh Exp $ SPRITE (Berkeley)";
  27. #endif /* not lint */
  28.  
  29.  
  30. #include <sprite.h>
  31. #include <mach.h>
  32. #include <proc.h>
  33. #include <sync.h>
  34. #include <sched.h>
  35. #include <procMigrate.h>
  36. #include <procInt.h>
  37. #include <migrate.h>
  38. #include <fs.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <sig.h>
  42. #include <spriteTime.h>
  43. #include <list.h>
  44. #include <byte.h>
  45. #include <vm.h>
  46. #include <sys.h>
  47. #include <rpc.h>
  48. #include <sysSysCall.h>
  49. #include <sysSysCallParam.h>
  50. #include <dbg.h>
  51. #include <stdio.h>
  52. #include <procUnixStubs.h>
  53. #include <bstring.h>
  54. #include <recov.h>
  55.  
  56. extern int debugProcStubs;
  57.  
  58.  
  59. /*
  60.  * An address for copy-out or make accessible is reasonable if it is not NIL.
  61.  */
  62.  
  63. #define ValidAddress(addr) (((Address) addr != (Address) NIL) && \
  64.                 ((Address) addr != (Address) USER_NIL))
  65.  
  66.     
  67.  
  68. /*
  69.  *----------------------------------------------------------------------
  70.  *
  71.  * ProcMigAcceptMigration --
  72.  *
  73.  *    Handle a request to start process migration.
  74.  *    This could check things like the number of remote processes,
  75.  *    load, or whatever. For now, just check against a global flag
  76.  *    that says whether to refuse migrations, and compare architecture
  77.  *    types and version numbers.  Allocate a process control block,
  78.  *    or match up with an existing shadow copy.
  79.  *
  80.  * Results:
  81.  *    SUCCESS is returned if permission is granted, and the local process
  82.  *        id of the process is returned.
  83.  *    PROC_MIGRATION_REFUSED is returned if the node is not accepting
  84.  *        migrated processes, or there is a version mismatch.
  85.  *    GEN_INVALID_ID is returned if some migrations are allowed but
  86.  *        the user is not permitted to migrate (e.g., only root is
  87.  *         allowed).
  88.  *
  89.  * Side effects:
  90.  *    A process may be allocated.
  91.  *
  92.  *----------------------------------------------------------------------
  93.  */
  94. /*ARGSUSED*/
  95. ReturnStatus
  96. ProcMigAcceptMigration(cmdPtr, procPtr, inBufPtr, outBufPtr)
  97.     ProcMigCmd *cmdPtr;/* contains ID of process on this host,
  98.                    or NIL */
  99.     Proc_ControlBlock *procPtr; /* ptr to process control block, or NIL */
  100.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  101.     Proc_MigBuffer *outBufPtr;    /* output buffer (default is empty) */
  102. {
  103.     ProcMigInitiateCmd *initPtr;
  104.     char machType[32];
  105.     int permMask;
  106.     Proc_PID *pidPtr;
  107.     int clientID;        /* Sprite ID of client host */
  108.  
  109.     if (proc_MigDebugLevel > 5) {
  110.     printf("ProcMigAcceptMigration called.\n");
  111.     }
  112.     if (inBufPtr->size != sizeof(ProcMigInitiateCmd)) {
  113.     /*
  114.      * Implicit version mismatch if they're not the same size.
  115.      */
  116.     if (proc_MigDebugLevel > 0) {
  117.         printf("Migration version mismatch: size of initiation request");
  118.         printf(" is %d, not %d.\n", inBufPtr->size,
  119.                sizeof(ProcMigInitiateCmd));
  120.         }
  121.     return(PROC_MIGRATION_REFUSED);
  122.     }
  123.  
  124.     initPtr = (ProcMigInitiateCmd *) inBufPtr->ptr;
  125.     clientID = initPtr->clientID;
  126.     if (initPtr->version != proc_MigrationVersion) {
  127.     if (proc_MigDebugLevel > 1) {
  128.         printf("Migration version mismatch: we are level %d; client %d is level %d.\n",
  129.            proc_MigrationVersion, clientID, initPtr->version);
  130.     }
  131.     return(PROC_MIGRATION_REFUSED);
  132.     }
  133.     if (cmdPtr->remotePid == (Proc_PID) NIL) {
  134.     /*
  135.      * Do various checks regarding whether we're accepting any migrations,
  136.      * then allocate a process.
  137.      */
  138.     if ((proc_AllowMigrationState & PROC_MIG_IMPORT_ALL) ==
  139.         PROC_MIG_IMPORT_NEVER) {
  140.         if (proc_MigDebugLevel > 4) {
  141.         printf("Warning: Proc_RpcMigInit: migration rejected because we are refusing migrations.\n");
  142.         }
  143.         return(PROC_MIGRATION_REFUSED);
  144.     }
  145.     if (initPtr->userID == PROC_SUPER_USER_ID) {
  146.         permMask = PROC_MIG_IMPORT_ROOT;
  147.     } else {
  148.         permMask = PROC_MIG_IMPORT_ALL;
  149.     }
  150.  
  151.     if ((proc_AllowMigrationState & permMask) != permMask) {
  152.         if (proc_MigDebugLevel > 2) {
  153.         printf("Proc_Migrate: user does not have permission to migrate.\n");
  154.         }
  155.         return(GEN_NO_PERMISSION);
  156.     }
  157.     
  158.     Net_SpriteIDToMachType(clientID, 32, machType);
  159.     if (*machType == '\0') {
  160.         printf("Warning: Proc_RpcMigInit: couldn't get machine type for client %d.\n",
  161.            clientID);
  162.         return(PROC_MIGRATION_REFUSED);
  163.     }
  164.     if (strcmp(machType, mach_MachineType)) {
  165.         if (proc_MigDebugLevel > 0) {
  166.         printf("Warning: Proc_RpcMigInit: client %d (%s) tried to migrate to this machine.\n",
  167.                clientID, machType);
  168.         }
  169.         return(PROC_MIGRATION_REFUSED);
  170.     }
  171.     /*
  172.      * Allocate a new process table entry for the migrating process.
  173.      */
  174.     procPtr = ProcGetUnusedPCB();
  175.     procPtr->peerProcessID = initPtr->processID;
  176.     procPtr->peerHostID = clientID;
  177.     procPtr->state = PROC_NEW;
  178.     procPtr->genFlags |= PROC_FOREIGN;
  179.  
  180.     pidPtr = (Proc_PID *) malloc(sizeof(Proc_PID));
  181.     *pidPtr = procPtr->processID;
  182.     Proc_Unlock(procPtr);
  183.     outBufPtr->ptr = (Address) pidPtr;
  184.     outBufPtr->size = sizeof(Proc_PID);
  185.  
  186.     /*
  187.      * Remember the dependency on the other host.
  188.      */
  189.     ProcMigAddDependency(procPtr->processID, procPtr->peerProcessID);
  190.     } else {
  191.     if (procPtr == (Proc_ControlBlock *) NIL) {
  192.         panic("ProcMigAcceptMigration: given null control block for existing process\n");
  193.         return(PROC_NO_PEER);
  194.     }
  195.     }
  196.     if (proc_MigDebugLevel > 5) {
  197.     printf("ProcMigAcceptMigration returning SUCCESS.\n");
  198.     }
  199.     return(SUCCESS);
  200. }
  201.  
  202.  
  203. /*
  204.  *----------------------------------------------------------------------
  205.  *
  206.  * ProcMigDestroyCmd --
  207.  *
  208.  *    Handle a request to destroy a migrated process, possibly
  209.  *    one that has not completed migration quite yet.
  210.  *
  211.  * Results:
  212.  *    SUCCESS.
  213.  *
  214.  * Side effects:
  215.  *    A process may be allocated.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219. /*ARGSUSED*/
  220. ReturnStatus
  221. ProcMigDestroyCmd(cmdPtr, procPtr, inBufPtr, outBufPtr)
  222.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  223.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  224.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  225.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays empty) */
  226. {
  227.     Proc_DestroyMigratedProc((ClientData) procPtr->processID, 
  228.                 (Proc_CallInfo *) NIL);
  229.     return(SUCCESS);
  230. }
  231.  
  232.  
  233. /*
  234.  *----------------------------------------------------------------------
  235.  *
  236.  * ProcMigContinueProcess --
  237.  *
  238.  *    Restore the state of a migrated process to its state prior to
  239.  *    migration.  If it is migrating home, remove the link between
  240.  *    the foreign copy of the process and this copy.  Add it to the
  241.  *    ready queue.
  242.  *
  243.  *
  244.  * Results:
  245.  *      A ReturnStatus.  (SUCCESS for now.)
  246.  *
  247.  * Side effects:
  248.  *    The process may be made runnable.
  249.  *
  250.  *----------------------------------------------------------------------
  251.  */
  252.  
  253. /*ARGSUSED*/
  254. ReturnStatus
  255. ProcMigContinueProcess(cmdPtr, procPtr, inBufPtr, outBufPtr)
  256.     ProcMigCmd *cmdPtr;/* contains ID of process on this host */
  257.     Proc_ControlBlock *procPtr; /* ptr to process control block */
  258.     Proc_MigBuffer *inBufPtr;    /* input buffer */
  259.     Proc_MigBuffer *outBufPtr;    /* output buffer (stays empty) */
  260. {
  261.     if (proc_MigDebugLevel > 10) {
  262.     printf(">> Entering debugger before continuing process %x.\n", procPtr->processID);
  263.     DBG_CALL;
  264.     }
  265.  
  266.     Proc_Lock(procPtr);
  267.     if (!(procPtr->genFlags & PROC_FOREIGN)) {
  268.     procPtr->peerProcessID = (Proc_PID) NIL;
  269.     procPtr->peerHostID = NIL;
  270.     }
  271.     procPtr->genFlags |= PROC_MIGRATION_DONE;
  272.     Proc_Unlock(procPtr);
  273.     Sched_MakeReady(procPtr);
  274.  
  275.     return(SUCCESS);
  276. }
  277.  
  278.  
  279. /*
  280.  *----------------------------------------------------------------------
  281.  *
  282.  * Proc_ResumeMigProc --
  283.  *
  284.  *    Resume a migrated user process.  This is the first thing that is
  285.  *     called when a migrated process continues execution.
  286.  *    If the process is actually performing a remote exec, then
  287.  *     call the routine to perform the exec, which won't return.
  288.  *
  289.  * Results:
  290.  *    Does not return.
  291.  *
  292.  * Side effects:
  293.  *    None.
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297.  
  298. void
  299. Proc_ResumeMigProc(pc)
  300.     int pc;        /* program counter to resume execution */
  301. {
  302.     register         Proc_ControlBlock *procPtr;
  303.  
  304.  
  305.     MASTER_UNLOCK(sched_MutexPtr);
  306.  
  307.     procPtr = Proc_GetCurrentProc();
  308.     Proc_Lock(procPtr);
  309.     if (procPtr->migFlags & PROC_EVICTING) {
  310.     /*
  311.      * Just to make sure we migrate back home ASAP...
  312.      */
  313.     Sig_SendProc(procPtr, SIG_MIGRATE_HOME, 0, (Address)0);
  314.     }
  315.     if (procPtr->genFlags & PROC_REMOTE_EXEC_PENDING) {
  316.     ProcDoRemoteExec(procPtr);
  317.     /*
  318.      * NOTREACHED
  319.      */
  320.     }
  321.     procPtr->genFlags &= ~PROC_NO_VM;
  322.     VmMach_ReinitContext(procPtr);
  323.     Proc_Unlock(procPtr);
  324.  
  325.     if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
  326.         procPtr->unixProgress != PROC_PROGRESS_UNIX) {
  327.     if (debugProcStubs) {
  328.         printf("Unix progress = %d (mig)\n", procPtr->unixProgress);
  329.     }
  330.     }
  331.     if (procPtr->unixProgress == PROC_PROGRESS_MIG_RESTART) {
  332.     if (debugProcStubs) {
  333.         printf("Restarting migrated system call\n");
  334.     }
  335.     procPtr->unixProgress = PROC_PROGRESS_RESTART;
  336.     }
  337.  
  338.     /*
  339.      * Start the process running.  This does not return.  
  340.      */
  341.  
  342.     Mach_StartUserProc(procPtr, (Address) pc);
  343.     panic("Proc_ResumeMigProc: Mach_StartUserProc returned.\n");
  344. }
  345.  
  346.  
  347. /*
  348.  *----------------------------------------------------------------------
  349.  *
  350.  * Proc_DoRemoteCall --
  351.  *
  352.  *    Generic system call handler for migrated processes.  This routine
  353.  *    takes a specification for the system call to invoke and the usage
  354.  *    of its parameters and sends them to the home node for processing.
  355.  *      Each parameter has a type and a disposition.  The type indicates
  356.  *    whether the parameter is an int, string, or other specialized
  357.  *     structure.  The disposition is "in", "out", or "in/out", as well
  358.  *    as whether the parameter should be accessed using Vm_Copy{In,Out}
  359.  *    or Vm_MakeAccessible.  The specific defined constants are documented
  360.  *    in sysSysCallParam.h.
  361.  *
  362.  *    All "in" or "in/out" parameters are sent in the RPC in the data
  363.  *    buffer.  All "out" or "in/out" parameters have space allocated for
  364.  *    them in the reply data buffer.  Strings and characters are padded
  365.  *    so that each field is aligned on an even address, so the actual
  366.  *    addresses within the buffers may be cast as integers and other types
  367.  *    without additional copying.
  368.  *
  369.  * Results:
  370.  *    A ReturnStatus is returned.  Values may be returned in the areas
  371.  *    referenced by pointers that are passed into the routine, but they
  372.  *    are dependent upon the system call invoked.
  373.  *
  374.  * Side effects:
  375.  *    A remote procedure call is performed.  
  376.  *
  377.  *----------------------------------------------------------------------
  378.  */
  379.  
  380. ReturnStatus
  381. Proc_DoRemoteCall(callNumber, numWords, argsPtr, specsPtr)
  382.     int callNumber;            /* number of system call to invoke */
  383.     int numWords;            /* number of words passed in */
  384.     ClientData *argsPtr;        /* pointer to data passed in */
  385.     Sys_CallParam *specsPtr;        /* array of information about the
  386.                      * parameters to this call */
  387. {
  388.     Proc_ControlBlock     *procPtr;    /* The migrated process */
  389.     int dataSize = 0;            /* size of the data buffer */
  390.     int replyDataSize = 0;        /* size of the reply buffer */
  391.     Address ptr;            /* place holder within buffer */
  392.     int *intArgsArray;            /* to treat argsPtr as array of ints */
  393.     int disp;                /* "disposition" of a parameter */
  394.     int type;                /* type of param (int, string, ...) */
  395.     int size;                /* number of bytes of a param */
  396.     int paddedSize;            /* likewise, padded to be aligned */
  397.     Proc_RemoteCall call;        /* parameter information for RPC */
  398.     Address pointerArray[SYS_MAX_ARGS]; /* array of made accessible pointers */
  399.     int numBytesAccessible[SYS_MAX_ARGS];/* number of bytes made accessible,
  400.                       * or zero if this variable has not
  401.                       * been made accessible */
  402.     Rpc_Storage storage;        
  403.     Address dataBuffer = (Address) NIL;
  404.     Address replyDataBuffer = (Address) NIL;
  405.     int i;
  406.     register ReturnStatus status;    /* returned by assorted procedures */
  407.     ReturnStatus remoteCallStatus;    /* status returned by system call */
  408.     Proc_TraceRecord record;        /* used to store trace data */
  409.     int lastArraySize = -1;            /* size of last array found */
  410.     int numTries;            /* number of times trying RPC */
  411.  
  412.     /*
  413.      * Create a synonym for argsPtr so that integer arguments can be referred
  414.      * to without casting them all the time.
  415.      */
  416.     
  417.     intArgsArray = (int *) argsPtr;
  418.     
  419.     
  420.     procPtr = Proc_GetActualProc();
  421.  
  422.     /*
  423.      * Check to make sure the home node is up, and kill the process if
  424.      * it isn't.  The call to exit never returns.
  425.      */
  426.     status = Recov_IsHostDown(procPtr->peerHostID);
  427.     if (status != SUCCESS) {
  428.     if (proc_MigDebugLevel > 0) {
  429.         printf("Proc_DoRemoteCall: host %d is down; killing process %x.\n",
  430.                procPtr->peerHostID, procPtr->processID);
  431.     }
  432.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  433.     /*
  434.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  435.      * directive causes a complaint when there's code after it.
  436.      */
  437.     panic("Proc_DoRemoteCall: Proc_ExitInt returned.\n");
  438.     return(PROC_NO_PEER);
  439.     }
  440.  
  441.     /*
  442.      * Set up the RPC parameters: pass the home processID, the system call
  443.      * number, and parameter information.  Additional parameter information
  444.      * (type and disposition) is copied below.
  445.      */
  446.  
  447.     call.processID = procPtr->peerProcessID;
  448.     call.callNumber = callNumber;
  449.     call.numArgs = numWords;
  450.     call.parseArgs = TRUE;
  451.  
  452. #ifndef CLEAN
  453.     if (proc_DoTrace && proc_DoCallTrace) {
  454.     record.processID = call.processID;
  455.     record.flags = PROC_MIGTRACE_START;
  456.     record.info.call.callNumber = callNumber;
  457.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  458.              (ClientData) &record);
  459.     }
  460. #endif /* CLEAN */   
  461.  
  462.     for (i = 0; i < numWords; i++) {
  463.     numBytesAccessible[i] = 0;
  464.     }
  465.  
  466.     /*
  467.      * Determine the type and size of each argument.  If the argument is
  468.      * a string, make it accessible now in order to find its size.
  469.      */
  470.  
  471.     for (i = 0; i < numWords; i++) {
  472.     disp = specsPtr[i].disposition;
  473.     type = specsPtr[i].type;
  474.     if ((disp & SYS_PARAM_OUT) &&
  475.         !(disp & (SYS_PARAM_ACC | SYS_PARAM_COPY))) {
  476.         panic("Proc_DoRemoteCall: Illegal parameter information for call %d for output parameter %d",
  477.               callNumber, i);
  478.         return(GEN_INVALID_ARG);
  479.     }
  480.     switch(type) {
  481.         case SYS_PARAM_INT:
  482.         case SYS_PARAM_CHAR: 
  483.         case SYS_PARAM_PROC_PID:
  484.         case SYS_PARAM_PROC_RES:
  485.         case SYS_PARAM_SYNC_LOCK:
  486.         case SYS_PARAM_FS_ATT:
  487.         case SYS_PARAM_TIMEPTR: 
  488.         case SYS_PARAM_TIME1:
  489.         case SYS_PARAM_TIME2:
  490.         case SYS_PARAM_RANGE1:
  491.         case SYS_PARAM_RANGE2:
  492.         case SYS_PARAM_PCB:
  493.         case SYS_PARAM_PCBARG:
  494.         case SYS_PARAM_VM_CMD:
  495.         case SYS_PARAM_DUMMY:
  496.             /*
  497.          * For typical arguments, the size may be found in a global
  498.          * array that is subscripted by the type.  If the argument
  499.          * is really an array, multiply by the number of arguments.
  500.          *
  501.          * Special case Proc_GetPCBInfo because it can allow
  502.          * a range of values or a PROC_MY_PID to specify one
  503.          * value.
  504.          */
  505.             if ((! (disp & SYS_PARAM_ARRAY)) ||
  506.                 (callNumber == SYS_PROC_GETPCBINFO &&
  507.                 intArgsArray[0] == PROC_MY_PID)) {
  508.             size = sys_ParamSizes[type];
  509.         } else {
  510.             /*
  511.              * The argument is actually a pointer to an array of
  512.              * the given type.  The size of the array is either
  513.              * the parameter just before the array pointer (an INT),
  514.              * or the difference between the two preceding arguments
  515.              * (RANGE1 and RANGE2).  Remember the size of the array,
  516.              * since a more arrays of the same size may follow.
  517.              *
  518.              */
  519.             if (i > 0 && specsPtr[i-1].type == SYS_PARAM_INT) {
  520.             size = (intArgsArray[i-1]) *
  521.                 sys_ParamSizes[type];
  522.             } else if (i > 1 && specsPtr[i-2].type ==
  523.                    SYS_PARAM_RANGE1 &&
  524.                    specsPtr[i-1].type == SYS_PARAM_RANGE2) {
  525.              if (type == SYS_PARAM_PCB) {
  526.                 intArgsArray[i-1] = intArgsArray[i-1] &
  527.                     PROC_INDEX_MASK;
  528.                 intArgsArray[i-2] = intArgsArray[i-2]  &
  529.                     PROC_INDEX_MASK;
  530.             }
  531.             size = (intArgsArray[i-1] - intArgsArray[i-2] + 1) *
  532.                 sys_ParamSizes[type];
  533.             } else if (i > 1 && (specsPtr[i-1].disposition
  534.                      & (SYS_PARAM_ARRAY))) {
  535.             size = lastArraySize;
  536.             } else {
  537.             panic("Proc_DoRemoteCall: bad parameter list.\n");
  538.             status = FAILURE;
  539.             goto failure;
  540.             }
  541.             lastArraySize = size;
  542.         }
  543.         break;
  544.         case SYS_PARAM_FS_NAME: 
  545.         case SYS_PARAM_HOSTNAME:
  546.                 /*
  547.          * The argument is a string.  If copying a string in, make
  548.          * it accessible and figure out its size dynamically.  If
  549.          * copying it out, just allocate space for the maximum number 
  550.          * of bytes for that type.
  551.          */
  552.         if ((disp & SYS_PARAM_ACC) && (disp & SYS_PARAM_IN)) {
  553.             status = Proc_MakeStringAccessible(sys_ParamSizes[type],
  554.                  (char **) &argsPtr[i], &numBytesAccessible[i], &size);
  555.             if (status != SUCCESS) {
  556.             if (proc_MigDebugLevel > 6) {
  557.                 panic("Proc_DoRemoteCall: status %x returned by Proc_MakeStringAccessible.\n", status);
  558.             }
  559.             goto failure;
  560.             }
  561.             /*
  562.               * Send the null byte as well.
  563.              */
  564.             size += 1;
  565.         } else if ((disp & SYS_PARAM_COPY) && (disp & SYS_PARAM_OUT)) {
  566.             size = sys_ParamSizes[type];
  567.         } else {
  568.             panic("Proc_DoRemoteCall: can't handle string parameter combination.\n");
  569.             status = FAILURE;
  570.             goto failure;
  571.         }
  572.         pointerArray[i] = (Address) argsPtr[i];
  573.         break;                    
  574.         default:
  575.         panic("Proc_DoRemoteCall: can't handle argument type.\n");
  576.         status = FAILURE;
  577.         goto failure;
  578.     }
  579.  
  580.     /*
  581.      * Store the information about this parameter.  If the argument is
  582.      * a pointer and it is USER_NIL, then store the fact that the
  583.      * parameter is NIL so that we won't try to copy out to that address
  584.      * later on, or to make it accessible.  Keep track of the sizes of the
  585.      * input and output buffers.  Make accessible anything that isn't
  586.      * already accessible.
  587.      */
  588.     call.info[i].size = size;
  589.     if ((disp & (SYS_PARAM_COPY | SYS_PARAM_ACC))
  590.             && !ValidAddress(argsPtr[i])) {
  591.         disp |= SYS_PARAM_NIL;
  592.     } else {
  593.         paddedSize = Byte_AlignAddr(size);
  594.         if (disp & SYS_PARAM_IN) {
  595.         dataSize += paddedSize;
  596.         }
  597.         if (disp & SYS_PARAM_OUT) {
  598.         replyDataSize += paddedSize;
  599.         }
  600.     }
  601.     call.info[i].disposition = disp;
  602.     if ((disp & SYS_PARAM_ACC) && numBytesAccessible[i] == 0) {
  603.         if (! (disp & SYS_PARAM_NIL)) {
  604.         int accessType; 
  605.  
  606.         if ((disp & SYS_PARAM_IN) && !(disp & SYS_PARAM_OUT)) {
  607.             accessType = VM_READONLY_ACCESS;
  608.         } else if (!(disp & SYS_PARAM_IN) && (disp & SYS_PARAM_OUT)) {
  609.             accessType = VM_OVERWRITE_ACCESS;
  610.         } else {
  611.             accessType = VM_READWRITE_ACCESS;
  612.         }
  613.         Vm_MakeAccessible(accessType, size, (Address) argsPtr[i],
  614.                   &numBytesAccessible[i], &pointerArray[i]);
  615.         if (numBytesAccessible[i] != size ||
  616.                 pointerArray[i] == (Address) NIL) {
  617.             status = SYS_ARG_NOACCESS;
  618.             goto failure;
  619.         }
  620.         } else {
  621.         pointerArray[i] = (Address) NIL;
  622.         }
  623.     }
  624.     }
  625.  
  626.     /*
  627.      * Now that the total sizes are known, allocate space and save the
  628.      * arguments in the data buffer.  While the RPC system and network
  629.      * driver are confused and screw up on buffers that are too small,
  630.      * pad the sizes accordingly.
  631.      */
  632.  
  633. #define RPC_MIN_BUFFER_SIZE 12
  634. #ifdef RPC_MIN_BUFFER_SIZE
  635.     if (dataSize < RPC_MIN_BUFFER_SIZE) {
  636.     dataSize = RPC_MIN_BUFFER_SIZE;
  637.     }
  638.     if (replyDataSize < RPC_MIN_BUFFER_SIZE) {
  639.     replyDataSize = RPC_MIN_BUFFER_SIZE;
  640.     }
  641. #endif /* RPC_MIN_BUFFER_SIZE */
  642.     
  643.     dataBuffer = (Address) malloc(dataSize);
  644.     ptr = dataBuffer;
  645.     replyDataBuffer = (Address) malloc(replyDataSize);
  646.     call.replySize = replyDataSize;
  647.  
  648.     for (i = 0; i < numWords; i++) {
  649.     disp = call.info[i].disposition;
  650.     if ((disp & SYS_PARAM_IN) && ! (disp & SYS_PARAM_NIL)) {
  651.         if (disp & SYS_PARAM_ACC) {
  652.         bcopy(pointerArray[i], ptr, call.info[i].size);
  653.         } else if (disp & SYS_PARAM_COPY) {
  654.         status = Vm_CopyIn(call.info[i].size, (Address) argsPtr[i],
  655.                    ptr);
  656.         if (status != SUCCESS) {
  657.             goto failure;
  658.         }
  659.         } else {
  660.         bcopy((Address) &argsPtr[i], ptr, call.info[i].size);
  661.         }
  662.     ptr += Byte_AlignAddr(call.info[i].size);
  663.     }
  664.     }
  665.  
  666.     /*
  667.      * Set up for the RPC.
  668.      */
  669.     storage.requestParamPtr = (Address) &call;
  670.     storage.requestParamSize = sizeof(Proc_RemoteCall);
  671.  
  672.     storage.requestDataPtr = dataBuffer;
  673.     storage.requestDataSize = dataSize;
  674.  
  675.     storage.replyParamPtr = (Address) NIL;
  676.     storage.replyParamSize = 0;
  677.     storage.replyDataPtr = replyDataBuffer;
  678.     storage.replyDataSize = replyDataSize;
  679.  
  680.     if (proc_MigDebugLevel > 4) {
  681.     printf("Proc_DoRemoteCall: sending call %d home.\n", callNumber); 
  682.     }
  683.  
  684.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  685.     remoteCallStatus = Rpc_Call(procPtr->peerHostID, RPC_PROC_REMOTE_CALL,
  686.                     &storage);
  687.     if (remoteCallStatus != RPC_TIMEOUT) {
  688.         break;
  689.     }
  690.     status = Proc_WaitForHost(procPtr->peerHostID);
  691.     if (status != SUCCESS) {
  692.         break;
  693.     }
  694.     }
  695.     if (proc_MigDebugLevel > 4) {
  696.     printf("Proc_DoRemoteCall: status %x returned by Rpc_Call.\n",
  697.            remoteCallStatus);
  698.     }
  699. #ifndef CLEAN
  700.     if (proc_DoTrace && proc_DoCallTrace) {
  701.     record.flags &= ~PROC_MIGTRACE_START;
  702.     record.info.call.status = remoteCallStatus;
  703.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  704.              (ClientData) &record);
  705.     }
  706. #endif /* CLEAN */   
  707.  
  708.     /*
  709.      * If we were told the process no longer exists on the home node,
  710.      * then blow it away.
  711.      */
  712.     if (remoteCallStatus == PROC_NO_PEER) {
  713.     if (proc_MigDebugLevel > 1) {
  714.         printf("Proc_DoRemoteCall: peer process %x is gone, killing %x.\n",
  715.            procPtr->peerProcessID, procPtr->processID);
  716.     }
  717.     status = PROC_NO_PEER;
  718.     (void) Sig_Send(SIG_KILL, (int) PROC_NO_PEER, procPtr->processID,
  719.             FALSE, (Address)0); 
  720.     goto failure;
  721.     }
  722.     /*
  723.      * Step through the reply data buffer and copy out any arguments that
  724.      * were output parameters.
  725.      */
  726.  
  727.     ptr = replyDataBuffer;
  728.     for (i = 0; i < numWords; i++) {
  729.     disp = call.info[i].disposition;
  730.     if (disp & SYS_PARAM_ACC) {
  731.         if ((disp & SYS_PARAM_OUT) && !(disp & SYS_PARAM_NIL)) {
  732.         bcopy(ptr, pointerArray[i], call.info[i].size);
  733.         ptr += Byte_AlignAddr(call.info[i].size);
  734.         }
  735.         if (numBytesAccessible[i] > 0) {
  736.         Vm_MakeUnaccessible(pointerArray[i], numBytesAccessible[i]);
  737.         numBytesAccessible[i] = 0;
  738.         }
  739.     } else if ((disp & SYS_PARAM_COPY) && (disp & SYS_PARAM_OUT)
  740.            && !(disp & SYS_PARAM_NIL)) {
  741.         size = call.info[i].size;
  742.         status = Vm_CopyOut(size, ptr, (Address) argsPtr[i]);
  743.         if (status != SUCCESS) {
  744.         if (proc_MigDebugLevel > 6) {
  745.             panic("Proc_DoRemoteCall: status %x returned by Vm_CopyOut.\n",
  746.                    status);
  747.         }
  748.  
  749.         status = SYS_ARG_NOACCESS;
  750.         goto failure;
  751.         }
  752.         ptr += Byte_AlignAddr(call.info[i].size);
  753.     }
  754.     }
  755.  
  756.     free(dataBuffer);
  757.     free(replyDataBuffer);
  758.     
  759.     return(remoteCallStatus);
  760.  
  761.  
  762.     /*
  763.      * Try to unwind after an error by making everything unaccessible
  764.      * again and freeing memory before returning the error condition.
  765.      * Note: if the procedure has progressed far enough for dataBuffer 
  766.      * to be non_NIL, then replyDataBuffer should be non-NIL then as well.
  767.      */
  768.  
  769. failure:
  770.  
  771.     for (i = 0; i < numWords; i++) {
  772.     if (numBytesAccessible[i] > 0) {
  773.         Vm_MakeUnaccessible(pointerArray[i], numBytesAccessible[i]);
  774.     }
  775.     }
  776.     if (dataBuffer != (Address) NIL) {
  777.     free(dataBuffer);
  778.     free(replyDataBuffer);
  779.     }
  780.     return(status);
  781. }
  782.  
  783.  
  784. /*
  785.  *----------------------------------------------------------------------
  786.  *
  787.  * Proc_RemoteDummy --
  788.  *
  789.  *    Dummy routine to return FAILURE for any system call not yet
  790.  *    implemented.
  791.  *
  792.  * Results:
  793.  *    FAILURE.
  794.  *
  795.  * Side effects:
  796.  *    None.  
  797.  *
  798.  *----------------------------------------------------------------------
  799.  */
  800.  
  801. /* ARGSUSED */
  802. ReturnStatus
  803. Proc_RemoteDummy(callNumber, numWords, argsPtr, specsPtr)
  804.     int callNumber;
  805.     int numWords;
  806.     Sys_ArgArray *argsPtr;
  807.     Sys_CallParam *specsPtr;
  808. {
  809.     printf("Warning: Call %d not yet implemented.\n", callNumber);
  810.     return(FAILURE);
  811. }
  812.  
  813.  
  814. /*
  815.  * ----------------------------------------------------------------------------
  816.  *
  817.  * ProcRemoteFork --
  818.  *
  819.  *    Perform an RPC to execute a fork on behalf of a migrated process.
  820.  *
  821.  * Results:
  822.  *    The status returned by the RPC is returned.
  823.  *
  824.  * Side effects:
  825.  *    An RPC is performed.  A skeletal process is created on the home node
  826.  *    to be the "real" process corresponding to the migrated forked process
  827.  *    that is in the process of being created.  The ID of the child on
  828.  *    the home node is stored in the PCB of the remote process.
  829.  *
  830.  * ----------------------------------------------------------------------------
  831.  */
  832.  
  833. ReturnStatus
  834. ProcRemoteFork(parentProcPtr, childProcPtr)
  835.     Proc_ControlBlock *parentProcPtr;    /* PCB for parent */
  836.     Proc_ControlBlock *childProcPtr;        /* PCB for child */
  837. {
  838.     Rpc_Storage storage;
  839.     Proc_RemoteCall call;
  840.     ReturnStatus status;
  841.     Proc_TraceRecord record;        /* used to store trace data */
  842.     int numTries;            /* number of times trying RPC */
  843.  
  844.     if (proc_MigDebugLevel > 3) {
  845.     printf("ProcRemoteFork called.\n");
  846.     }
  847.  
  848.     status = Recov_IsHostDown(parentProcPtr->peerHostID);
  849.     if (status != SUCCESS) {
  850.     if (proc_MigDebugLevel > 0) {
  851.         printf("ProcRemoteFork: host %d is down; killing process %x.\n",
  852.                parentProcPtr->peerHostID, parentProcPtr->processID);
  853.     }
  854.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  855.     /*
  856.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  857.      * directive causes a complaint when there's code after it.
  858.      */
  859.     panic("ProcRemoteFork: Proc_ExitInt returned.\n");
  860.     return(PROC_NO_PEER);
  861.     }
  862.  
  863. #ifndef CLEAN
  864.     if (proc_DoTrace && proc_DoCallTrace) {
  865.     record.processID = parentProcPtr->peerProcessID;
  866.     record.flags = PROC_MIGTRACE_START;
  867.     record.info.call.callNumber = SYS_PROC_FORK;
  868.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  869.              (ClientData) &record);
  870.     }
  871. #endif /* CLEAN */   
  872.  
  873.     /*
  874.      * Set up for the RPC.
  875.      */
  876.     call.processID = parentProcPtr->peerProcessID;
  877.     call.callNumber = SYS_PROC_FORK;
  878.     call.parseArgs = FALSE;
  879.     storage.requestParamPtr = (Address) &call;
  880.     storage.requestParamSize = sizeof(Proc_RemoteCall);
  881.  
  882.     storage.requestDataPtr = (Address) &childProcPtr->processID;
  883.     storage.requestDataSize = sizeof(int);
  884.  
  885.     storage.replyParamPtr = (Address) NIL;
  886.     storage.replyParamSize = 0;
  887.     storage.replyDataPtr = (Address) &childProcPtr->peerProcessID;
  888.     storage.replyDataSize = sizeof(Proc_PID);
  889.  
  890.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  891.     status = Rpc_Call(parentProcPtr->peerHostID, RPC_PROC_REMOTE_CALL,
  892.                &storage);
  893.     if (status != RPC_TIMEOUT) {
  894.         break;
  895.     }
  896.     status = Proc_WaitForHost(parentProcPtr->peerHostID);
  897.     if (status != SUCCESS) {
  898.         break;
  899.     }
  900.     }
  901.  
  902. #ifndef CLEAN
  903.     if (proc_DoTrace && proc_DoCallTrace) {
  904.     record.flags &= ~PROC_MIGTRACE_START;
  905.     record.info.call.status = status;
  906.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  907.              (ClientData) &record);
  908.     }
  909. #endif /* CLEAN */   
  910.  
  911.     /*
  912.      * If we were told the process no longer exists on the home node,
  913.      * then blow it away.  Any other return status just means we didn't
  914.      * initialize the child properly.
  915.      */
  916.     if (status != SUCCESS) {
  917.     if (status == PROC_NO_PEER) {
  918.         (void) Sig_Send(SIG_KILL, (int) PROC_NO_PEER,
  919.                 parentProcPtr->processID, FALSE, (Address)0); 
  920.     }
  921.     if (proc_MigDebugLevel > 0) {
  922.         printf("Warning: ProcRemoteFork returning status %x.\n",
  923.                status);
  924.     }
  925.     return(status);
  926.     }
  927.     childProcPtr->peerHostID = parentProcPtr->peerHostID;
  928.     childProcPtr->genFlags |= PROC_FOREIGN;
  929.     childProcPtr->kcallTable = mach_MigratedHandlers;
  930.  
  931.     /*
  932.      * Note the dependency of the new process on the other host.
  933.      */
  934.     ProcMigAddDependency(childProcPtr->processID, childProcPtr->peerProcessID);
  935.  
  936.     /*
  937.      * Update statistics.
  938.      */
  939.     PROC_MIG_INC_STAT(foreign);
  940.  
  941.     if (proc_MigDebugLevel > 3) {
  942.     printf("ProcRemoteFork returning status %x.\n", status);
  943.     }
  944.     return(status);
  945. }
  946.  
  947.  
  948. /*
  949.  *----------------------------------------------------------------------
  950.  *
  951.  * ProcRemoteExit --
  952.  *
  953.  *    Cause a migrated process to exit.  Throw away its address space, but
  954.  *     migrate runtime information back to the home node.  
  955.  *
  956.  * Results:
  957.  *    None.
  958.  *
  959.  * Side effects:
  960.  *    A remote procedure call is performed and the part of the
  961.  *     process state that survives past Proc_Exit is transferred.
  962.  *
  963.  *----------------------------------------------------------------------
  964.  */
  965.  
  966. void
  967. ProcRemoteExit(procPtr, reason, exitStatus, code)
  968.     register Proc_ControlBlock     *procPtr;  /* process that is exiting */
  969.     int reason;    /* Why the process is dying: EXITED, SIGNALED, DESTROYED  */
  970.     int    exitStatus;    /* Exit status or signal # or destroy status */
  971.     int code;    /* Signal sub-status */
  972. {
  973.     Address buffer;
  974.     Address ptr;
  975.     int bufferSize;
  976.     Rpc_Storage storage;
  977.     Proc_RemoteCall call;
  978.     ReturnStatus status;
  979.     Proc_TraceRecord record;        /* used to store trace data */
  980.     int numTries;            /* number of times trying RPC */
  981.  
  982.     if (proc_MigDebugLevel > 4) {
  983.     printf("ProcRemoteExit(%x) called.\n", exitStatus);
  984.     }
  985.  
  986.     /*
  987.      * Update statistics.
  988.      */
  989.     if (!(procPtr->genFlags & PROC_DONT_MIGRATE)) {
  990.     PROC_MIG_DEC_STAT(foreign);
  991.     } else {
  992.     if (proc_MigDebugLevel > 3) {
  993.         printf("ProcRemoteExit: process %x is foreign but unmigratable.\n",
  994.            procPtr->processID);
  995.     }
  996.     }
  997.     if ((procPtr->migFlags & PROC_EVICTING) ||
  998.     (proc_MigStats.foreign == 0 &&
  999.      proc_MigStats.evictionsInProgress != 0)) {
  1000.     ProcMigEvictionComplete();
  1001.     }
  1002.  
  1003.  
  1004.     status = Recov_IsHostDown(procPtr->peerHostID);
  1005.     if (status != SUCCESS) {
  1006.     if (proc_MigDebugLevel > 0) {
  1007.         printf("ProcRemoteExit: host %d is down; ignoring exit for process %x.\n",
  1008.                procPtr->peerHostID, procPtr->processID);
  1009.     }
  1010.     /*
  1011.      * Remove the dependency on the other host, but note that the host
  1012.      * is down now.
  1013.      */
  1014.     ProcMigRemoveDependency(procPtr->processID, FALSE);
  1015.     return;
  1016.     }
  1017.  
  1018.     ProcMigRemoveDependency(procPtr->processID, TRUE);
  1019. #ifndef CLEAN
  1020.     if (proc_DoTrace && proc_DoCallTrace) {
  1021.     record.processID = procPtr->processID;
  1022.     record.flags = PROC_MIGTRACE_START;
  1023.     record.info.call.callNumber = SYS_PROC_EXIT;
  1024.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  1025.              (ClientData) &record);
  1026.     }
  1027. #endif /* CLEAN */   
  1028.  
  1029.  
  1030.     bufferSize = 2 * sizeof(Timer_Ticks) + 5 * sizeof(int);
  1031.     buffer = (Address) malloc(bufferSize);
  1032.  
  1033.     ptr = buffer;
  1034.     Byte_FillBuffer(ptr, Timer_Ticks,  procPtr->kernelCpuUsage.ticks);
  1035.     Byte_FillBuffer(ptr, Timer_Ticks,  procPtr->userCpuUsage.ticks);
  1036.     Byte_FillBuffer(ptr, int,  procPtr->numQuantumEnds);
  1037.     Byte_FillBuffer(ptr, int,  procPtr->numWaitEvents);
  1038.     Byte_FillBuffer(ptr, int, reason);
  1039.     Byte_FillBuffer(ptr, int, exitStatus);
  1040.     Byte_FillBuffer(ptr, int, code);
  1041.  
  1042.  
  1043.     /*
  1044.      * Set up for the RPC.
  1045.      */
  1046.     call.processID = procPtr->peerProcessID;
  1047.     call.callNumber = SYS_PROC_EXIT;
  1048.     call.parseArgs = FALSE;
  1049.     storage.requestParamPtr = (Address) &call;
  1050.     storage.requestParamSize = sizeof(Proc_RemoteCall);
  1051.  
  1052.     storage.requestDataPtr = buffer;
  1053.     storage.requestDataSize = bufferSize;
  1054.  
  1055.     storage.replyParamPtr = (Address) NIL;
  1056.     storage.replyParamSize = 0;
  1057.     storage.replyDataPtr = (Address) NIL;
  1058.     storage.replyDataSize = 0;
  1059.  
  1060.  
  1061.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  1062.     status = Rpc_Call(procPtr->peerHostID, RPC_PROC_REMOTE_CALL, &storage);
  1063.     if (status != RPC_TIMEOUT) {
  1064.         break;
  1065.     }
  1066.     status = Proc_WaitForHost(procPtr->peerHostID);
  1067.     if (status != SUCCESS) {
  1068.         break;
  1069.     }
  1070.     }
  1071.  
  1072. #ifndef CLEAN
  1073.     if (proc_DoTrace && proc_DoCallTrace) {
  1074.     record.flags &= ~PROC_MIGTRACE_START;
  1075.     record.info.call.status = status;
  1076.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  1077.              (ClientData) &record);
  1078.     }
  1079. #endif /* CLEAN */   
  1080.  
  1081.     free(buffer);
  1082.  
  1083.     if ((status != SUCCESS) && (proc_MigDebugLevel > 0)) {
  1084.     printf("Warning: ProcRemoteExit received status %x.\n", status);
  1085.     }
  1086. }
  1087.  
  1088.  
  1089. /*
  1090.  *----------------------------------------------------------------------
  1091.  *
  1092.  * ProcRemoteExec --
  1093.  *
  1094.  *    Tell the home node of a process that it has done an exec, and to
  1095.  *     change any information it might have about effective IDs.  
  1096.  *
  1097.  * Results:
  1098.  *    None.
  1099.  *
  1100.  * Side effects:
  1101.  *    A remote procedure call is performed.
  1102.  *
  1103.  *----------------------------------------------------------------------
  1104.  */
  1105.  
  1106. void
  1107. ProcRemoteExec(procPtr, uid)
  1108.     register Proc_ControlBlock     *procPtr;  /* process that is doing exec */
  1109.     int uid;                   /* new effective user ID, or -1 */
  1110. {
  1111.     Address buffer;
  1112.     Address ptr;
  1113.     int bufferSize;
  1114.     Rpc_Storage storage;
  1115.     Proc_RemoteCall call;
  1116.     ReturnStatus status;
  1117.     Proc_TraceRecord record;        /* used to store trace data */
  1118.     int numTries;            /* number of times trying RPC */
  1119.  
  1120.     if (proc_MigDebugLevel > 4) {
  1121.     printf("ProcRemoteExec(%s) called.\n", procPtr->argString);
  1122.     }
  1123.  
  1124.     status = Recov_IsHostDown(procPtr->peerHostID);
  1125.     if (status != SUCCESS) {
  1126.     if (proc_MigDebugLevel > 0) {
  1127.         printf("ProcRemoteExec: host %d is down; killing process %x.\n",
  1128.                procPtr->peerHostID, procPtr->processID);
  1129.     }
  1130.     Proc_Unlock(procPtr);
  1131.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  1132.     /*
  1133.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  1134.      * directive causes a complaint when there's code after it.
  1135.      */
  1136.     panic("ProcRemoteExec: Proc_ExitInt returned.\n");
  1137.     return;
  1138.     }
  1139.  
  1140.  
  1141. #ifndef CLEAN
  1142.     if (proc_DoTrace && proc_DoCallTrace) {
  1143.     record.processID = procPtr->processID;
  1144.     record.flags = PROC_MIGTRACE_START;
  1145.     record.info.call.callNumber = SYS_PROC_EXEC;
  1146.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  1147.              (ClientData) &record);
  1148.     }
  1149. #endif /* CLEAN */   
  1150.  
  1151.  
  1152.  
  1153.     bufferSize = sizeof(int) + strlen(procPtr->argString) + 1;
  1154.     buffer = (Address) malloc(bufferSize);
  1155.  
  1156.     ptr = buffer;
  1157.     Byte_FillBuffer(ptr, int,  uid);
  1158.     (void) strcpy(ptr,  procPtr->argString);
  1159.  
  1160.  
  1161.     /*
  1162.      * Set up for the RPC.
  1163.      */
  1164.     call.processID = procPtr->peerProcessID;
  1165.     call.callNumber = SYS_PROC_EXEC;
  1166.     call.parseArgs = FALSE;
  1167.     storage.requestParamPtr = (Address) &call;
  1168.     storage.requestParamSize = sizeof(Proc_RemoteCall);
  1169.  
  1170.     storage.requestDataPtr = buffer;
  1171.     storage.requestDataSize = bufferSize;
  1172.  
  1173.     storage.replyParamPtr = (Address) NIL;
  1174.     storage.replyParamSize = 0;
  1175.     storage.replyDataPtr = (Address) NIL;
  1176.     storage.replyDataSize = 0;
  1177.  
  1178.  
  1179.     /*
  1180.      * Unlock the process while we're doing the RPC.
  1181.      */
  1182.     Proc_Unlock(procPtr);
  1183.     
  1184.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  1185.     status = Rpc_Call(procPtr->peerHostID, RPC_PROC_REMOTE_CALL, &storage);
  1186.     if (status != RPC_TIMEOUT) {
  1187.         break;
  1188.     }
  1189.     status = Proc_WaitForHost(procPtr->peerHostID);
  1190.     if (status != SUCCESS) {
  1191.         break;
  1192.     }
  1193.     }
  1194.  
  1195.     /*
  1196.      * Give the process back the way it was handed to us (locked).
  1197.      */
  1198.     Proc_Lock(procPtr);
  1199.  
  1200. #ifndef CLEAN
  1201.     if (proc_DoTrace && proc_DoCallTrace) {
  1202.     record.flags &= ~PROC_MIGTRACE_START;
  1203.     record.info.call.status = status;
  1204.     Trace_Insert(proc_TraceHdrPtr, PROC_MIGTRACE_CALL,
  1205.              (ClientData) &record);
  1206.     }
  1207. #endif /* CLEAN */   
  1208.  
  1209.  
  1210.     free(buffer);
  1211.  
  1212.     if ((status != SUCCESS) && (proc_MigDebugLevel > 0)) {
  1213.     printf("Warning: ProcRemoteExec received status %x.\n", status);
  1214.     }
  1215. }
  1216.  
  1217.  
  1218.